package com.xxl.job.admin.core.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.xxl.job.admin.core.model.AccessToken;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 使用Hutool JWT生成类似OAuth2标准的AccessToken
 * 支持自定义声明、签名验证和有效期管理
 */
public class JwtAccessTokenGenerator {
    // 默认密钥（实际生产环境应使用更安全的随机密钥并妥善保管）
//    private static final byte[] DEFAULT_SECRET = "yourSecureSecretKey1234567890".getBytes();
    // 默认有效期（2小时，单位：秒）
    private static final long DEFAULT_EXPIRE_TIME = 7200;
    // 默认刷新令牌有效期（30天，单位：秒）
    private static final long DEFAULT_REFRESH_EXPIRE_TIME = 2592000;

    // 签名算法（HS256：HMAC + SHA-256）
    private final JWTSigner signer;
    private final byte[] secret;
    private long expireTime;
    private long refreshExpireTime;

    /**
     * 构造函数（使用默认配置）
     */
    public JwtAccessTokenGenerator(String secret) {
        this(secret, DEFAULT_EXPIRE_TIME, DEFAULT_REFRESH_EXPIRE_TIME);
    }

    /**
     * 构造函数（自定义配置）
     */
    public JwtAccessTokenGenerator(String secret, long expireTime, long refreshExpireTime) {
        this.secret = secret.getBytes(StandardCharsets.UTF_8);
        this.expireTime = expireTime;
        this.refreshExpireTime = refreshExpireTime;
        this.signer = JWTSignerUtil.hs256(this.secret);
    }

    /**
     * 生成AccessToken
     *
     * @param subject 主题（通常是用户ID或客户端ID）
     * @param claims  自定义声明
     * @return 包含token和过期时间的Map
     */
    public AccessToken generateToken(String subject, Map<String, Object> claims) {
        // 生成唯一ID（使用兼容Hutool 5.8.x的写法）
        String jti = UUID.randomUUID().toString();

        // 当前时间和过期时间
        Date now = new Date();
        Date expireDate = DateUtil.offsetSecond(now, (int) expireTime);

        // 构建JWT（使用兼容Hutool 5.8.x的写法）
        JWT jwt = JWT.create()
                .setHeader("typ", "JWT")       // 令牌类型
                .setHeader("alg", "HS256")     // 签名算法
                .setPayload("jti", jti)        // JWT唯一标识
                .setPayload("iss", "yourApp")  // 发行人
                .setPayload("sub", subject)    // 主题
                .setPayload("iat", now)        // 签发时间
                .setPayload("exp", expireDate); // 过期时间

        // 添加自定义声明（兼容Hutool 5.8.x的写法）
        for (Map.Entry<String, Object> entry : claims.entrySet()) {
            jwt.setPayload(entry.getKey(), entry.getValue());
        }

        // 生成签名后的Token
        String accessToken = jwt.sign(signer);

        // 生成刷新令牌
        String refreshToken = generateRefreshToken(jti, subject, now);

        // 返回结果
        AccessToken accessTokenData = new AccessToken();
        accessTokenData.setAccessToken(accessToken)
                .setRefreshToken(refreshToken)
                .setTokenType("Bearer")
                .setExpiresIn(expireTime);

        return accessTokenData;
    }

    /**
     * 生成刷新令牌
     */
    private String generateRefreshToken(String jti, String subject, Date issuedAt) {
        Date refreshExpireDate = DateUtil.offsetSecond(issuedAt, (int) refreshExpireTime);

        return JWT.create()
                .setHeader("typ", "JWT")
                .setHeader("alg", "HS256")
                .setPayload("jti", jti + "_refresh")
                .setPayload("iss", "yourApp")
                .setPayload("sub", subject)
                .setPayload("iat", issuedAt)
                .setPayload("exp", refreshExpireDate)
                .sign(signer);
    }

    /**
     * 验证Token有效性
     *
     * @param token JWT字符串
     * @return 是否有效
     */
    public boolean validateToken(String token) {
        try {
            // 验证签名
            boolean verify = JWTUtil.verify(token, signer);
            if (!verify) {
                return false;
            }

            // 验证有效期
            JWTValidator.of(token).validateDate(new Date());

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 解析Token获取Claims
     *
     * @param token JWT字符串
     * @return Claims
     */
    public Map<String, Object> parseToken(String token) {
        if (!validateToken(token)) {
            return null;
        }

        JWT jwt = JWT.of(token);

        // 解析Claims（兼容Hutool 5.8.x的写法）
        Map<String, Object> claims = new HashMap<>();
        for (String key : jwt.getPayload().getClaimsJson().keySet()) {
            claims.put(key, jwt.getPayload().getClaim(key));
        }

        return claims;
    }

    /**
     * 刷新AccessToken
     *
     * @param refreshToken 刷新令牌
     * @return 新的AccessToken
     */
    public AccessToken refreshToken(String refreshToken) {
        if (!validateToken(refreshToken)) {
            throw new IllegalArgumentException("无效的刷新令牌");
        }

        JWT jwt = JWT.of(refreshToken);
        String subject = (String) jwt.getPayload().getClaim("sub");

        // 从刷新令牌中提取原始JTI
        String jti = (String) jwt.getPayload().getClaim("jti");
        jti = jti.replace("_refresh", "");

        // 生成新的AccessToken（使用相同的JTI和Subject）
        Map<String, Object> claims = new HashMap<>();
        claims.put("jti", jti);
        return generateToken(subject, claims);
    }

    /**
     * 获取过期时间
     * @return
     */
    public Long getExpireTime() {
        return this.expireTime;
    }

    /**
     * 设置Token有效期（秒）
     */
    public JwtAccessTokenGenerator setExpireTime(long expireTime) {
        this.expireTime = expireTime;
        return this;
    }

    /**
     * 设置刷新令牌有效期（秒）
     */
    public JwtAccessTokenGenerator setRefreshExpireTime(long refreshExpireTime) {
        this.refreshExpireTime = refreshExpireTime;
        return this;
    }

    // 示例用法
    public static void main(String[] args) {
        // 创建生成器实例
        JwtAccessTokenGenerator generator = new JwtAccessTokenGenerator("default_token");

        // 自定义声明
        Map<String, Object> claims = new HashMap<>();
        claims.put("role", "admin");
        claims.put("scope", "read_write");

        // 生成Token
        AccessToken tokenResult = generator.generateToken("admin", claims);
        String accessToken = tokenResult.getAccessToken();
        String refreshToken = tokenResult.getRefreshToken();

        System.out.println("生成的AccessToken: " + accessToken);
        System.out.println("生成的RefreshToken: " + refreshToken);
        System.out.println("有效期: " + tokenResult.getExpiresIn() + "秒");


        generator = new JwtAccessTokenGenerator("cdzysoft");

        // 验证Token
        boolean isValid = generator.validateToken(accessToken);
        System.out.println("Token有效性: " + isValid);

        // 解析Token
        Map<String, Object> parsedClaims = generator.parseToken(accessToken);
        System.out.println("解析的Claims: " + parsedClaims);

        // 刷新Token
        AccessToken refreshedResult = generator.refreshToken(refreshToken);
        System.out.println("刷新后的AccessToken: " + refreshedResult.getAccessToken());
    }
}